import { _decorator, clamp, Collider2D, Component, ERaycast2DType, ERigidBody2DType, EventTouch, IPhysics2DContact, Node, PhysicsSystem2D, RaycastResult2D, Sprite, Tween, tween, UITransform, v2, v3, Vec2, Vec3 } from 'cc';
import { Item } from './Item';
import { EasingType } from '../../Scripts/Framework/Utils/TweenUtil';
import { PolygonPlane } from './GameItems/PolygonPlane';
import { MigaManager } from './MigaManager';
import { Person } from './Person';
import { TweenTag } from './Subject';
import { AudioManager } from '../../Scripts/Framework/Managers/AudioManager';
const { ccclass, property } = _decorator;

@ccclass('ItemFloor')
export class ItemFloor extends Item {

    @property(Node)
    inside: Node;

    @property(Collider2D)
    floor: Collider2D;

    @property([Collider2D])
    floors: Collider2D[] = [];

    TouchEnd(event: EventTouch): void {
        if (!this.isTouch) return;
        MigaManager.Instance.edgePoint = null;
        this.isMove = false;
        Tween.stopAllByTag(TweenTag.Touch, this.node);
        tween(this.node).tag(TweenTag.Touch)
            .to(0.1, { scale: Vec3.ONE })
            .start();
        this.touchUpPos = this.node.getPosition();
        this.isTouch = false;
        if (this.canTouchUse) this.node.children[0].active = false;
        if (this.isInfusion && this.infusion) {
            let sf = this.infusion.spriteFrame;
            this.infusion.spriteFrame = this.sprite.spriteFrame;
            this.sprite.spriteFrame = sf;
            this.Raycast(event.getUILocation());
            this.floor && this.inside.active && (this.floor.enabled = false);
            if (this.floors && this.inside.active) {
                for (let i = 0; i < this.floors.length; i++) {
                    const element = this.floors[i];
                    element.enabled = false;
                }
            }
        }
        else if (this.handTarget && this.handPerson) {
            this.handPerson.Hand(this);
            Tween.stopAllByTag(TweenTag.Angle, this.node);
            tween(this.node)
                .to(0.5, { angle: this.handAngle }, { easing: EasingType.circOut })
                .start();
            if (MigaManager.Instance.tutorial.active) MigaManager.Instance.NextTutorial();
        }
        else if (this.sitTarget) {
            this.node.setParent(this.sitTarget, true);
            let otherWidth = this.sitTarget.getComponent(UITransform).width;
            let delta = this.sitTarget.getWorldPosition().x - this.node.getWorldPosition().x;
            let pos = v3(this.node.getWorldPosition().x, this.sitTarget.getWorldPosition().y);
            if (otherWidth < this.uiTransform.width) pos.x = this.sitTarget.getWorldPosition().x;
            else if (delta > otherWidth / 2 - this.width / 2) pos.x = this.sitTarget.getWorldPosition().x - otherWidth / 2 + this.width / 2;
            else if (delta < this.width / 2 - otherWidth / 2) pos.x = this.sitTarget.getWorldPosition().x + otherWidth / 2 - this.width / 2;
            Tween.stopAllByTag(TweenTag.FallCollid, this.node);
            tween(this.node).tag(TweenTag.FallCollid)
                .to(0.2, { worldPosition: pos })
                .start();
        }
        else {
            this.Raycast(event.getUILocation());
            this.floor && this.inside.active && (this.floor.enabled = false);
            if (this.floors && this.inside.active) {
                for (let i = 0; i < this.floors.length; i++) {
                    const element = this.floors[i];
                    element.enabled = false;
                }
            }
        }
    }

    ChangeSf(): void {
        if (this.isMove) return;
        if (this.sfIndex == 1 && !this.canReverse || this.changeSfs.length == 0) return;
        this.sfIndex = this.sfIndex == 0 ? 1 : 0;
        this.sprite.spriteFrame = this.changeSfs[this.sfIndex];
        this.collider.size.width = this.uiTransform.width;
        this.collider.size.height = this.uiTransform.height;
        this.collider.offset = v2((0.5 - this.uiTransform.anchorX) * this.uiTransform.width, (0.5 - this.uiTransform.anchorY) * this.uiTransform.height);
        this.collider.apply();
        if (this.clip) AudioManager.Instance.PlaySFX(this.clip);
        this.inside.active = !this.inside.active;
        this.floor.enabled = !this.floor.enabled;
        this.node.children[2].active = !this.node.children[2].active;
    }

    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null): void {
        let other = otherCollider.node;
        let itemFloor = other.parent.getComponent("ItemFloor") as any;
        if (otherCollider.group == 1 << 1) this.personTarget = other.getComponent(Person);
        if (otherCollider.group == 1 << 4 && this.canHand) this.handPerson = other.parent.getComponent(Person);
        if (otherCollider.group == 1 << 11) this.headPerson = other.parent.getComponent(Person);
        if (otherCollider.group == 1 << 12 && this.isInfusion) this.infusion = other.getComponent(Sprite);
        if (otherCollider.group == 1 << 2 || otherCollider.group == 1 << 6 && itemFloor.size > this.size || otherCollider.group == 1 << 7 && other.getComponent(PolygonPlane).size > this.size) {
            if (!this.isTouch && this.rig.gravityScale > 0) {
                this.floor && this.inside.active && (this.floor.enabled = true);
                if (this.floors && this.inside.active) {
                    for (let i = 0; i < this.floors.length; i++) {
                        const element = this.floors[i];
                        element.enabled = true;
                    }
                }
                if (other.getComponent(PolygonPlane)?.layer) this.otherplane = other.getComponent(PolygonPlane);
                if (other == this.rayTarget) {
                    if (other.getComponent(PolygonPlane)?.floorBox) this.node.setParent(other.getComponent(PolygonPlane).floorBox.node, true);
                    else this.node.setParent(MigaManager.Instance.game.children[0], true);
                    if (other.getComponent(PolygonPlane)?.box) this.otherBox = other.getComponent(PolygonPlane)?.box;
                    this.rig.gravityScale = 0;
                    this.rig.linearVelocity = Vec2.ZERO;
                    let v = v3(0, 0);
                    if (otherCollider.group == 1 << 6 && other.parent.getComponent(Item).size > this.size) {
                        this.scheduleOnce(() => { this.rig.type = ERigidBody2DType.Animated; });
                        this.rig.enabledContactListener = false;
                        this.collider.enabled = false;
                        this.node.setParent(itemFloor.inside, true);
                        let otherUI = other.getComponent(UITransform);
                        let dx = this.node.getWorldPosition().x - other.getWorldPosition().x;
                        let limitX: number;
                        limitX = (otherUI.width - this.uiTransform.width) / 2 * (dx > 0 ? 1 : -1);
                        if (limitX > 0 && dx > limitX - 20 || limitX < 0 && dx < limitX + 20) v.x = -(dx - limitX);
                    }
                    else if (otherCollider.group == 1 << 7) {
                        let plane = other.getComponent(PolygonPlane);
                        if (plane) {
                            if (plane.box && plane.box.size > this.size) this.node.setParent(plane.box.node, true);
                            let otherUI = other.getComponent(UITransform);
                            let dx = this.node.getWorldPosition().x - other.getWorldPosition().x;
                            let limitX: number;
                            let y = this.node.getWorldPosition().y - this.uiTransform.height * (1 - this.uiTransform.anchorY);
                            if (plane.mul != 0) {
                                let deltaX = otherUI.height * plane.mul;
                                let topY = other.getWorldPosition().y + otherUI.height * (1 - otherUI.anchorY);
                                let per = Math.max((topY - y) / otherUI.height, 0);
                                limitX = (otherUI.width / 2 - deltaX * per) * (dx > 0 ? 1 : -1);
                            }
                            else limitX = (otherUI.width - this.uiTransform.width) / 2 * (dx > 0 ? 1 : -1);
                            if (limitX > 0 && dx > limitX - 20 || limitX < 0 && dx < limitX + 20) v.x = -(dx - limitX);
                        }
                    }
                    let ratio = clamp(Math.abs(this.touchUpPos.y - other.getPosition().y), 0, 2000) / 2000;
                    Tween.stopAllByTag(TweenTag.FallCollid, this.node);
                    tween(this.node).tag(TweenTag.FallCollid)
                        .by(0.2, { position: v3(v.x, 0) }, { easing: EasingType.sineOut })
                        .start();
                }
                else {
                    if (this.collidTarget && other != this.collidTarget) return;
                    if (other.getComponent(PolygonPlane)?.floorBox) this.node.setParent(other.getComponent(PolygonPlane).floorBox.node, true);
                    else this.node.setParent(MigaManager.Instance.game.children[0], true);
                    if (other.getComponent(PolygonPlane)?.box) this.otherBox = other.getComponent(PolygonPlane)?.box;
                    this.rig.gravityScale = 0;
                    this.rig.linearVelocity = Vec2.ZERO;
                    let v = v3(0, 0);
                    if (otherCollider.group == 1 << 6 && other.parent.getComponent(Item).size > this.size) {
                        this.scheduleOnce(() => { this.rig.type = ERigidBody2DType.Animated; });
                        this.rig.enabledContactListener = false;
                        this.collider.enabled = false;
                        this.node.setParent(itemFloor.inside, true);
                        let otherUI = other.getComponent(UITransform);
                        let dx = this.node.getWorldPosition().x - other.getWorldPosition().x;
                        let limitX: number;
                        limitX = (otherUI.width - this.uiTransform.width) / 2 * (dx > 0 ? 1 : -1);
                        if (limitX > 0 && dx > limitX - 20 || limitX < 0 && dx < limitX + 20) v.x = -(dx - limitX);
                    }
                    else if (otherCollider.group == 1 << 7) {
                        let plane = other.getComponent(PolygonPlane);
                        if (plane) {
                            if (plane.box && plane.box.size > this.size) this.node.setParent(plane.box.node, true);
                            let otherUI = other.getComponent(UITransform);
                            let dx = this.node.getWorldPosition().x - other.getWorldPosition().x;
                            let limitX: number;
                            let y = this.node.getWorldPosition().y - this.uiTransform.height * (1 - this.uiTransform.anchorY);
                            if (plane.mul != 0) {
                                let deltaX = otherUI.height * plane.mul;
                                let topY = other.getWorldPosition().y + otherUI.height * (1 - otherUI.anchorY);
                                let per = Math.max((topY - y) / otherUI.height, 0);
                                limitX = (otherUI.width / 2 - deltaX * per) * (dx > 0 ? 1 : -1);
                            }
                            else limitX = (otherUI.width - this.uiTransform.width) / 2 * (dx > 0 ? 1 : -1);
                            if (limitX > 0 && dx > limitX - 20 || limitX < 0 && dx < limitX + 20) v.x = -(dx - limitX);
                        }
                    }
                    Tween.stopAllByTag(TweenTag.FallCollid, this.node);
                    let y = this.node.getWorldPosition().y - other.getWorldPosition().y - this.uiTransform.height / 2 * this.uiTransform.anchorY / 0.5;
                    if (y < 0) v.y = -y + 10;
                    tween(this.node).tag(TweenTag.FallCollid)
                        .by(0.2, { position: v })
                        .start();
                }
            }
            else if (!this.collidTarget || this.collidTarget.getWorldPosition().y > other.getWorldPosition().y) this.collidTarget = other;
        }
        else if (otherCollider.group == 1 << 3) {
            if (other.getComponent(PolygonPlane) && other.getComponent(PolygonPlane).size <= this.size) return;
            if (this.isTouch) this.sitTarget = other;
            else if (this.rig.gravityScale > 0) {
                this.floor && this.inside.active && (this.floor.enabled = true);
                if (this.floors && this.inside.active) {
                    for (let i = 0; i < this.floors.length; i++) {
                        const element = this.floors[i];
                        element.enabled = true;
                    }
                }
                this.rig.gravityScale = 0;
                this.rig.linearVelocity = Vec2.ZERO;
                this.node.setParent(other, true);
                let otherWidth = other.getComponent(UITransform).width;
                let delta = other.getWorldPosition().x - this.node.getWorldPosition().x;
                let pos = v3(this.node.getWorldPosition().x, other.getWorldPosition().y);
                if (otherWidth < this.uiTransform.width) pos.x = other.getWorldPosition().x;
                else if (delta > otherWidth / 2 - this.width / 2) pos.x = other.getWorldPosition().x - otherWidth / 2 + this.width / 2;
                else if (delta < this.width / 2 - otherWidth / 2) pos.x = other.getWorldPosition().x + otherWidth / 2 - this.width / 2;
                Tween.stopAllByTag(TweenTag.FallCollid, this.node);
                tween(this.node).tag(TweenTag.FallCollid)
                    .to(0.2, { worldPosition: pos })
                    .start();
            }
        }
    }

}
